package com.algorithm.qap;

import com.algorithm.basic.BasicMoead;
import com.problem.qap.QAPProblem;
import com.util.bean.METHOD;
import com.util.solution.impl.QAPSolution;

public class MOEAD extends BasicMoead{
	private QAPProblem problem;
	private int run_num;
	private int niche = 30;
	private int method;
	
	public MOEAD(QAPProblem problem, int run_num, int method){
		super(problem.obj_num, -1);
		this.problem = problem;
		this.run_num = run_num;
		this.method = method;
		weights = new double[problem.sub_num*problem.obj_num];
		nicheNeighbors = new int[problem.sub_num][niche];
		initialWeights(problem.sub_num, niche);
		this.bind(this.problem, this.method);
	}
	
	public void execute(int iteration){
		long startMili=System.currentTimeMillis();
		for(int i = 0;i<iteration;i++){
			System.out.println("iteration of : "+(i+1));
			this.executeMoead();
		}
		long endMili=System.currentTimeMillis();
		System.out.println((endMili-startMili)/1000+" s ");
		String fileName = null;
		if(this.method==METHOD.WS){
			fileName = "files/results/qap/moead/"+problem.fac_num+"-"+problem.obj_num+"/"+this.problem.corr+"/"+problem.fac_num+"_"+problem.obj_num+"_ws_"+run_num+".txt";
		}else if(this.method==METHOD.TCH){
			fileName = "files/results/qap/moead/"+problem.fac_num+"-"+problem.obj_num+"/"+this.problem.corr+"/"+problem.fac_num+"_"+problem.obj_num+"_tch_"+run_num+".txt";
		}else{
			fileName = "files/results/qap/moead/"+problem.fac_num+"-"+problem.obj_num+"/"+this.problem.corr+"/"+problem.fac_num+"_"+problem.obj_num+"_pbi_"+run_num+".txt";
		}
		problem.saveResults(fileName);
	}
	public void executeMoead(){
		for(int i=0;i<problem.sub_num;i++){
			QAPSolution curSolution = problem.solutionArray[i];
			if(curSolution.isSearched()==false){
				problem.solutionArray[i].setSearched(true);
				try {
					QAPSolution s = curSolution.clone();
					this.generateNeighborhood(s);
				} catch (CloneNotSupportedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	/**
	 * generate the neighborhood
	 * @param s
	 */
	public void generateNeighborhood(QAPSolution s){
		int [] seq = s.getLocations().clone();
		for(int i=0;i<problem.fac_num;i++){
			for(int j=i+1;j<problem.fac_num;j++){
				int [] changedVal = new int[problem.obj_num];
				for(int k=0;k<problem.obj_num;k++) changedVal[k] = 0;
				for(int k=0;k<problem.obj_num;k++){
					for(int t=0;t<this.problem.fac_num;t++){
						changedVal[k] += 2*(this.problem.distMatrix[i*this.problem.fac_num+t]*this.problem.flowMatrix[k*this.problem.fac_num*this.problem.fac_num+seq[i]*this.problem.fac_num+seq[t]]);
						changedVal[k] += 2*(this.problem.distMatrix[j*this.problem.fac_num+t]*this.problem.flowMatrix[k*this.problem.fac_num*this.problem.fac_num+seq[j]*this.problem.fac_num+seq[t]]);
					}
				}
				QAPSolution temp = new QAPSolution(this.problem.fac_num, this.problem.obj_num, -1);
				temp.setLocations(seq.clone());
				temp.locations[i] = seq[j];
				temp.locations[j] = seq[i];
				for(int k=0;k<this.problem.obj_num;k++){
					for(int t=0;t<this.problem.fac_num;t++){
						changedVal[k] -= 2*(this.problem.distMatrix[i*this.problem.fac_num+t]*this.problem.flowMatrix[k*this.problem.fac_num*this.problem.fac_num+temp.locations[i]*this.problem.fac_num+temp.locations[t]]);
						changedVal[k] -= 2*(this.problem.distMatrix[j*this.problem.fac_num+t]*this.problem.flowMatrix[k*this.problem.fac_num*this.problem.fac_num+temp.locations[j]*this.problem.fac_num+temp.locations[t]]);
					}
				}
				int t_count = 0;
				for(int k=0;k<this.problem.obj_num;k++){
					if(changedVal[k]<=0){
						t_count++;
					}
				}
				if(t_count==this.problem.obj_num){
					continue;
				}
				for(int k=0;k<this.problem.obj_num;k++) temp.object_val[k] = s.object_val[k] - changedVal[k];
				temp.index = s.index;
				this.udpateSubSolutions(temp);
			}
		}
	}
	public boolean udpateSubSolutions(QAPSolution s){
		this.udpateIdealPoint(s.object_val);
		boolean ret = false;
		for(int i=0;i<niche;i++){
			QAPSolution curSolution = problem.solutionArray[this.nicheNeighbors[s.index][i]];
			double fitness = 0;
			if(this.method == METHOD.WS){
				curSolution.fitness = getWsValue(curSolution.index, curSolution.object_val);
				fitness = getWsValue(curSolution.index, s.object_val);
			}else if(this.method == METHOD.TCH){
				curSolution.fitness = getTchValue(curSolution.index, curSolution.object_val);
				fitness = getTchValue(curSolution.index, s.object_val);
			}else{
				curSolution.fitness = getPbiValue(curSolution.index, curSolution.object_val);
				fitness = getPbiValue(curSolution.index, s.object_val);
			}
			if(curSolution.fitness>fitness){
				curSolution.fitness = fitness;
				curSolution.object_val = s.object_val.clone();
				curSolution.locations = s.locations.clone();
				curSolution.setSearched(false);
				ret = true;
			}
		}
		return ret;
	}
	public static void main(String[]args){
		for(int k=0;k<3;k++){
			for(int i=0;i<20;i++){
				QAPProblem problem = new QAPProblem();
				MOEAD moead = new MOEAD(problem, i, k);
				moead.execute(1000);
			}
		}
	}
}
